#pragma once
#include <shared_mutex>
#include <memory>
#include <queue>
#include <set>

#include "my_utility.hpp"
#include "socket.hpp"
#include "log.hpp"

namespace ns_interface
{
    // 校验服务器单例控制器
    class examiner_server_controller
    {
    private:
        // 校验服务器信息
        class examiner_server_info
        {
        public:
            examiner_server_info(const std::string& ip = "0.0.0.0", short port = 0) noexcept;
            examiner_server_info(const examiner_server_info& other);
            examiner_server_info(examiner_server_info&& other);
            const examiner_server_info& operator=(const examiner_server_info& other);
            const examiner_server_info& operator=(examiner_server_info&& other);

            // 连接校验服务器
            int connect();

            // 断开校验服务器
            void disconnect(int fd);

            // 获取连接数
            unsigned int getValue() const noexcept;

            // 获取服务器id
            std::string getKey() const noexcept;
        private:
            // 服务器端口
            short _port;
            // 服务器ip
            std::string _ip;
            // 网络结构体
            sockaddr_in _server_msg;
            // 网络结构体长度
            socklen_t _server_msg_len;
            // 服务器负载
            std::atomic<unsigned int> _load;
        };
    private:
        using info_ptr = std::shared_ptr<examiner_server_info>;
    private:
        examiner_server_controller();
        ~examiner_server_controller();

        // 加载校验服务器地址
        void loadSetting();
    public:
        // 申请校验服务使用权
        std::pair<int, size_t> connect();

        // 归还校验服务使用权
        void disconnect(std::pair<int, size_t> fd_and_index);

        // 校验服务器上线
        void serverOnline(const std::string& address, short port);

        // 校验服务器下线
        void serverOffline(size_t index);

        // 校验服务器是否为空
        bool empty() const noexcept;
    private:
        // 校验服务器数组
        std::vector<examiner_server_info> _server_arr;
        // 校验服务器是否为空
        std::set<std::string> _is_server_exist;
        // 校验服务器是否可信
        std::set<std::string> _server_believable;
        // 共享锁
        std::shared_mutex _ctrl;
    public:
        // 控制器指针
        static examiner_server_controller* _instance_ptr;
    };
}